Welcome back.
In this lecture, we're going to give the ability for our player to sprint inside of the model where
we all grab the game assets.
There is also a GUI for the starter GUI called the stamina GUI.
So let me enable UI visibility so we can go ahead and take a look at this guy.
And inside of here.
It's a very simple guy.
It's just one frame and another frame inside of it.
One of them is a border and the other is a fill inside of this border.
And all this is going to represent is a simple bar that shows the player's stamina as they continue
sprinting.
This bar is going to slowly go down until it reaches zero.
Once it reaches zero, then we're going to force a cooldown on this player where they're going to have
to wait for their stamina to replenish and come back up so they can start sprinting again.
So let me go ahead and make these transparent again, and you'll see why we've done that in a little
bit.
Then I'll disable it and let me close out UI visibility.
And now what we're going to do is we're going to create a new script inside of starter character scripts.
It's going to be a local script.
And the reason we're putting this inside of starter character scripts is because we want our script
to be destroyed, and we want a new one to be copied when our players die and they respawn.
Because all of these scripts inside of starter character scripts are going to be copied into our player's
character.
And then when that character dies and it gets deleted, all of these scripts along with it get deleted,
and then a new set of scripts get copied into the new character model.
Inside of here.
We're going to be using that same template that we've been using before.
We're going to get rid of this section as well as this section.
And what we're going to need to do is we're going to need to listen for a user's input.
Specifically, for most games, when you want to sprint, you'll typically hold down the left shift
key.
So the best way for us to listen for that user input, as well as listen for across multiple different
devices would be to use the Context action service.
So we'll go ahead and grab the Context Action service.
And then we're also going to need the player service in order to grab the stamina guy or create a reference
to that guy so we can go ahead and manipulate it to show how much stamina we currently have.
So we'll get the player service as well.
And of course, we're also going to want to use the tween service to fade our stamina guy in and out
of the screen.
So, for example, if we're not sprinting in, all of our stamina has been filled up, then we want
to fade the guy out.
And then once we start sprinting and using stamina, we want to fade the guy back in.
So we're going to need to use the tween service for that.
And the last but not least, we're going to want to constantly listen or update the stamina for the
player basically every single frame.
So the other service we're going to need is the run service.
Now, how this is going to work is we're going to use the context action service, and we're going to
bind an action to a specific set of inputs.
So we'll create a new action here.
I'm just going to call this action sprint.
And then we can go ahead and bind our function.
And this will get passed the action name the input state as well as our input object.
So we'll do that.
If we would like to create a touch button, I'm going to do true.
So that way we can add support for mobile devices.
And then the other input that we want to listen to is going to be the enum dot key code dot left shift.
And now inside of this function we want to do is we want to make sure that the input state is equal
to the enum dot user input state of begin, or the user input state of end.
So that way we can keep track of when they start sprinting and when they release and stop sprinting.
So we can check if either it's in the begin input state, or if the input state is equal to the enum
dot user input state dot end.
And what we can go ahead and do is we can create a variable to keep track of whether or not we are currently
sprinting.
So I'll create a variable, I'll call it shift down.
And by default we're going to set that to false.
But when we start sprinting we're going to set shift down equal to true.
And then when we stop sprinting we're going to set shift down back equal to false.
And then another thing we're going to have to keep track of is the player's stamina.
So we're also going to want to have a variable that, uh, contains what our current stamina is.
So I'll just call it current stamina.
And by default we're going to set that at a value of 100.
So we can either go to zero or up to 100.
Now of course we don't want to set shift down equal to true if we do not have enough stamina.
So if our current stamina is, um, less than or equal to zero, then we're just going to return because
we don't want to let the player sprint.
Now, another thing that we can do to make it look like our player is sprinting is that we can also
tween the field of view of the player's camera.
So if you've ever played a game and you sprint in a game, you can see that your camera kind of zooms
out and then when you stop sprinting, it kind of zooms back in.
That's us shifting or changing the field of view of the camera.
So what we could do is we could create two dedicated functions, one to start sprinting and one to stop
sprinting.
Where the start sprinting will update the walk speed of our humanoid and then zoom out the camera a
little bit, and then the stop function will zoom the camera back to its original field of view, and
then reset.
The humanoids walk speed back to its default.
So what we're going to go ahead and do is create several constants to keep track of a bunch of information.
For example, what speed would we like to set the character to when they sprint?
We could call it sprint speed, and we could set it to a value of like 22 studs per second.
Another constant we could keep track of is what is the regular or default speed for our humanoid.
So we could call this a regular speed.
And that means we're going to have to grab our humanoid.
So up here I'll create a variable one to refer to our character.
And that's going to just be equal to script dot parent, because this script is going to be a child
of our player's character.
And actually let's go ahead and rename this script to our sprint handler.
And then we can also go ahead and grab the humanoid, which is going to be equal to the character,
and we'll use wait for child just in case.
And then we can go ahead and grab our humanoid.
And then we'll also make a quick reference to the GUI as well.
So that's going to be inside of our player.
So let's make a quick reference to the player as well.
So players dot local player.
And then GUI is going to be equal to our player.
And that's going to be in the player GUI folder.
And we want to go ahead and wait for the stamina GUI.
And then we can go ahead and set regular speed equal to our humanoids walk speed.
And then some other constants we want to go ahead and define is what's our maximum stamina that we can
have.
So we can call this max stamina.
And we could just set it to 100.
And then we also want to define how fast we want to replenish or drain away our stamina.
So I could create some constants like stamina reduce.
And we'll just set it to some arbitrary value like 32.
And then we could do another one.
We'll call it stamina increase.
And we'll set it equal to like 16.
So basically what I want these values to represent is that every single second our stamina is going
to be reduced by 32.
And then every single second our stamina is going to be increased by 16.
So our stamina as it stands currently should last us about a little over three seconds.
Of course, you can change these values to whatever you like, but I'm just going to set them to these
for now.
And then we also want to define what our field of view should be when we're sprinting, and what our
default field of view is.
So we'll call this sprint field of view.
And if we go ahead and look in the workspace and look at our camera, the default field of view is 70.
So we could set it to something a little bit higher like 85.
And then we can also store the regular field of view.
And that means we're going to have to grab the camera.
So I'll make a variable for the camera real quick.
We'll just call this camera.
And that's equal to workspace dot current camera.
And the regular field of view is going to be equal to our camera dot field of view.
And then we can also define how long we would like to wait before we start replenishing stamina if we've
drained through all of it.
So we could call this our sprint cooldown.
Or you could call it our stamina cooldown and we could set it to something like five seconds.
So the player is going to have to wait five seconds if they let their stamina drain all the way down
to zero.
But now what we could go ahead and do is we could create two functions.
One function we could call start sprint, and then the other one we could call reset speed.
So this one will have a start sprinting and will zoom the field of view of the camera out, and then
we'll reset our walk speed back to default and zoom the camera back in.
So inside of our start sprint function, what we want to do is we want to check if the camera's field
of view is not equal to the sprint field of view.
If it isn't, then that means we're going to want to tween the field of view of the camera to match
our sprint field of view.
So we use the tween service we'll create on our camera.
We could do a tween info dot new of like 0.8 seconds, and then we want to change the field of view
of our camera to be equal to the sprint field of view, and then we can go ahead and play this tween.
And then we also want to set the humanoids walk speed equal to our sprint speed.
And then for the reset speed function, we'll just copy this.
But instead this time we want to check if the field of view of the camera is not equal to the original
field of view or defaults.
What do I call it?
Regular.
Yeah.
Regular field of view.
And if it isn't, then we want to set it to the regular field of view and then reset the walk speed
to the default or regular walk speed.
So speed.
Regular speed.
There we go.
So any time we press down shift and we have enough stamina, then we're going to start our sprint.
Otherwise when we let go of the shift key, then we're going to stop our sprint or reset the speed of
our character.
Now the thing is, as we hold down shift, we're going to want to drain the player's stamina.
And then when it hits zero, we're going to want to reset the speed of the player.
So we're going to have to listen to the run service heartbeat event and connect a function to this.
And this is where we're going to update every single frame to drain the stamina.
If the shift down variable is equal to true.
Now, another important thing to note is that this function gets passed something called a delta time.
Delta time.
And this variable represents the amount of time between frames.
So how long did it take at the start of one frame to the start of the next frame.
And if your game is running at 60 frames per second, then the time between those two frames is going
to be about 0.016 seconds.
However, this delta time is important, and that's because if we're draining the stamina of our player
based on their frame rate or based on how fast this heartbeat updates, if a player is playing the game
at a lower or higher frame rate, and we do not take into account this delta time value, then the stamina
is either going to reduce faster or slower for some players.
But if we want to keep it consistent between all players in our game, regardless of their frame rate,
then we need to use delta time in our calculations.
So in this heartbeat event, what we're going to do is we're going to check if we're holding down shift,
and we're also going to want to check and make sure that our current stamina is greater than the value
of zero.
And we also want to make sure that our player is actually moving.
And to demonstrate this, what I'm going to do real quick is I'm going to denote this as a humanoid,
because the linter or basically studio doesn't know the type of this humanoid.
So when I type it out, as you can see, it doesn't really auto fill any important information.
So I'm just going to use some type annotation real quick.
You don't need to worry about what this is, but it's going to help, uh, studio recognize that this
variable is storing a humanoid.
So when I go and type it out now, I get auto filled with all the stuff that belongs to a humanoid.
Because when I go down here, I want to make sure that the humanoid dot move direction property, it
says, describes the direction that the humanoid is walking in.
And we're going to get the magnitude of that vector.
We want to make sure that's greater than zero, which confirms to us that the humanoid or this player
is actually walking.
So if we're holding down shift, we have enough stamina and we're actually moving, then that means
we want to drain the stamina of our player.
So we want to update the value of current stamina to be minus equal to the stamina reduce.
And then we want to multiply this value by our delta time.
So we're going to multiply it by delta time.
So that way we keep it consistent.
Or we're reducing the stamina consistently across multiple different frame rates.
Otherwise if our stamina for example reaches zero then we want to force a cooldown.
So what we could do is we could create another boolean.
And I'm going to call this sprinting cooldown.
And by default we're going to set it to false.
But what we're going to check here is we're going to check if we are not in a sprinting cooldown.
If we're not in a sprinting cooldown, then we need to check if we don't have any stamina.
So if our current stamina is less than or equal to zero and we're not in a sprinting cooldown, well
then we need to force a sprinting cooldown.
So what we're going to do is we're going to set sprinting cooldown equal to true.
We're going to set current stamina equal to zero.
And now what we want to do is we want to reset the speed of our player because we're out of stamina.
So we'll do reset speed.
And then we basically want to like delay a function from executing, which is going to allow us to start
replenishing stamina.
Because another thing we want to check is that if we are not holding down shift.
So if our current stamina is less than our maximum stamina.
And we want to make sure that we can actually replenish stamina.
So if current stamina is less than our maximum stamina, um, we need to create a variable to keep track
of whether or not we can actually replenish stamina.
So I'm going to create a variable called can replenish stamina.
And by default we're going to set that to true.
And then what we're going to do is when we reach a sprinting cool down, we want to set can replenish
stamina equal to false.
And then we're also going to want to set shift down equal to false.
We're basically resetting everything because we're out of stamina.
And then we want to delay a function from executing.
And that delay is going to be equal to our sprint cooldown.
And once that sprint cooldown is up, then we can set can replenish stamina back to true to let our
function connected to our heartbeat know that hey, we can start replenishing stamina.
So in this if statement right here, when our current stamina is less than our max stamina, then we
want to verify that we can actually replenish stamina.
So if we cannot replenish stamina, then we're just going to return because we are on our cooldown,
so we don't want to replenish any stamina.
Otherwise, we want to make sure that we're not holding down shift or our player's character is not
moving.
So if we are not holding down the shift key or our humanoids move direction property, get the magnitude
of that.
If that's less than or equal to zero, then we can go ahead and replenish stamina right here because
our player could hold down shift, but their character could not be moving.
So we want to still make sure that we're replenishing stamina for them.
So this time we're going to set current stamina plus equal to.
And then we're going to get our stamina increase.
And then also multiply this by our delta time.
And then inside of here we're also going to want to make sure that because we can replenish stamina
just in case we're going to set sprinting cooldown back to false because we don't set a sprinting cooldown
to false up here.
But we do it down here because when it tells us that we can replenish stamina, then it's going to hop
in here.
It's going to make sure we can replenish stamina, and then it'll set sprinting cooldown equal to false
for us.
And now, since here we are tracking the stamina of our player.
What we're going to want to do is, while our current stamina is less than our max stamina, we want
to update our stamina bar so we could create a dedicated function to update the stamina bar to set the
bar equal to whatever percentage stamina we have left.
So let's go ahead and create a function.
And I'm going to call this function Update Stamina bar.
And we're going to call this function inside of this if statement.
So we're only going to update our stamina bar when we've noticed that our current stamina is less than
our maximum stamina.
So inside of this function, what we're going to want to do is since by default, our stamina guy is
going to be hidden and not on the screen, we want to check if our stamina guy is hidden, and if it
is, we want to unhide it and fade it onto the screen.
Because we have been using stamina and we want to display that to the player.
So if our guy is not enabled, then we want to make sure our guy is enabled.
And then we want to go ahead and tween the fill as well as the outline for the fill.
We want to update their transparency properties to be opaque.
So again we're going to use the tween service.
So tween service create.
One's going to be on the outline.
And then another one is going to be on our fill frame.
And then for the tween info dot new, we could do something like fade it in for like 0.3 seconds.
And we want to make sure we update the transparency to be opaque.
So equal to zero.
And then we can copy this and do the same thing for our fill frame.
But for the fill frame, it doesn't have a transparency property, but it does have a background transparency
property.
And then we can go ahead and play these two tweens to fade the guy onto our screen.
And then now we also want to, um, update that bar or the fill frame once we've displayed the guy on
the screen.
So what we could do is refer to our guy, get the border, and then get the fill frame.
And we want to update its size, and its size is going to be equal to a new Utum two.
And we're going to do from scale.
And then for the x axis, that's just going to be equal to one because our stamina bar is a vertical.
So we want to update it on the y axis.
So the y axis is going to be equal to our current stamina.
And we're going to divide it by our max stamina to get our percentage.
So if our current stamina is 100 and our max stamina is 100, then that's a value of one.
So it will be completely filled.
But if our current stamina is like 50.
Then it's going to be half.
So the Y scale is going to be 0.5.
So we'll see that we only have half of our stamina.
And then one more thing we want to go ahead and check for is we want to check for if our stamina is
at 100.
If it is, then we want to fade the guy back out.
So one way for us to check it is we can check if our stamina, if our current stamina is equal to 100.
Or another way we could check it is if our guy dot border dot fill dot size on the y scale if that size
is equal to one.
And then we also want to make sure that it hasn't been faded out yet.
So we can also check if the guy dot boarder dot outline dot transparency is still equal to zero.
And then let me go ahead and wrap this all up.
So that way the interpreter knows how to interpret this if statement.
So if either current stamina is equal to 100, or the Y scale on our UI is set to one, and we haven't
faded it out yet because the transparency is still set to zero, then we need to fade out our UI.
So I'm just going to copy what we did up here.
But this time we want to set the transparency to one.
And then I'm going to grab one of these tweens.
So I'll just call this tween.
Make, get rid of that and then we'll play this tween.
And then we want to listen for when this tween completes.
Because when this tween completes we want to go ahead and disable our guy.
So we'll set guy dot enabled equal to false.
Okay.
We should now have everything we need set up for our sprint system.
So when we press down the left shift key, we're going to set shift down equal to true.
And we're going to start sprinting.
Then it's going to check if we are currently holding down shift and we are moving and we have enough
stamina.
It's going to reduce our stamina.
Once we recognize that our stamina is less than or equal to zero, we're going to update its value equal
to zero, and we're going to force a cooldown.
And while we're forcing this cooldown can replenish.
Stamina is set to false, which tells this section of code right here that hey, you can't replenish
stamina, so don't do anything.
Otherwise, if we can replenish stamina, then we're going to make sure that we're not holding down
shift, or we're going to make sure that our humanoid is not walking.
If we aren't, then we're going to go ahead and restore the stamina for our player.
And once we do that, we can go ahead and update the stamina bar.
And when we update the stamina bar, that's either going to fade in or fade out the guy on our screen,
depending on how much stamina we have, and we're updating the size of our fill frame to be equal to
the percentage of how much stamina we have.
Now, one more thing we could do is that we could listen for when our humanoid dies.
And when our humanoid dies, we want to go ahead and stop listening to this input right here, because
we can't sprint when we're dead.
So we could use the context action service and unbind the action of sprint when our humanoid dies.
Other than that, I think we should be good to go.
This was a lot of code to write without testing anything.
So let's go ahead and actually playtest our game and see if we are able to sprint.
So we'll hit play here.
Spawn in the map.
Here's my player if I hold down shift.
As you can see, the screen zooms out as I start walking.
Boom!
We're running.
We're reducing stamina.
And then when I let go, as you can see, the stamina is replenishing itself.
And it got to the full amount, but unfortunately it is not fading out.
So let's go ahead and figure out why that is the case.
But otherwise it does appear that our stamina system is indeed working.
When we sprint, the camera zooms out and then when we stop, it zooms back in.
Let me go ahead and hit stamina zero.
There we go.
Now we're in a force cooldown and I can no longer sprint.
And now we're able to replenish, and then I can sprint again.
So it looks like the only thing we need to troubleshoot is why our GUI is not disappearing when we hit
max stamina.
Okay, I think one reason why it might not exactly be working is because our current stamina could go
above the value of 100 when we're increasing it here.
So what we could do to account for that is instead of set this from equal to to be greater than or equal
to.
So if the current stamina is greater than or equal to 100, then we can go ahead and fade out the guy.
So let's go ahead and test that out and see how that would work.
So if I go on sprint and then stop.
There we go.
Perfect.
Our guy fades out and it's no longer visible on the screen.
And then when I start sprinting again, it reappears on the screen.
And then when the bar goes back up and our current stamina perfect as you can see, it fades back out
again.
Beautiful.
That's all from me for this lecture.
I hope you enjoyed and I'll see you in the next one.